#include "Sort.h"

#include <iomanip>

#include <string>

using namespace std;

/******************************************************************************
 *
 * Définition de la classe Sort
 *
 *****************************************************************************/

/** Constructeur par défaut.
 * Les écoles sont numérotées de 0 à 20. Un sort inexistant est
 * construit en appelant le constructeur par défaut. Le sort "nul"
 * sert de valeur de retour quand on veut accéder à un sort qui
 * n'existe pas (dépassement d'index par exemple).
 *
 * @param[in] ecole numéro de l'école de magie (défaut = 0).
 * @param[in] niveau niveau du sort (défaut = 0).
 * @param[in] numero numéro du sort (défaut = 0).
 */
Sort::Sort( const unsigned& ecole, const unsigned& niveau,
	    const unsigned& numero )
  : ADDObjetBase( "Sort" ), Ecole( ecole ), Niveau( niveau ),
    Numero( numero )
{}

/** Constructeur de copie.
 * Effectue une copie propre d'un sort dans un autre. Normalement ceci
 * ne devrait pas causer de problèmes, mais comme il existe plusieurs
 * fonctions qui retournent un Sort...
 *
 * @param[in] m_sort sort à copier.
 */
Sort::Sort( const Sort& m_sort )
  : ADDObjetBase( "Sort" ), Ecole( m_sort.Ecole ),
    Niveau( m_sort.Niveau ), Numero( m_sort.Numero )
{}

/**
 * Destructeur, ne fait rien de spécial.
 */
Sort::~Sort()
{}

/** Opérateur d'affectation.
 * Permet de réaliser une copie "nette" d'une instance dans un autre,
 * lorsques la destination nexiste déjà.
 *
 * @param[in] m_sort sort à copier.
 *
 * @return référence constante sur l'instance courante.
 */
const Sort& Sort::operator=( const Sort& m_sort )
{
  Ecole  = m_sort.Ecole;
  Niveau = m_sort.Niveau;
  Numero = m_sort.Numero; 

  return *this;
}

/** Opérateur de comparaison "plus petit", nécessaire pour le tri.
 * La comparaison est effectuée de la manière suivante :\n
 * 1) on compare les écoles.
 * 2) si les écoles sont les mêmes, on compare les niveaux.\n
 * 3) si les écoles et les niveaux sont les mêmes, on compare les numéros.
 *
 * Cela permet d'obtenir un conteneur où les sorts sont groupés par
 * écoles, puis par niveau et apparaissent par ordre alphabétique.
 *
 * @param[in] m_sort sort à comparer
 *
 * @return valeur du test
 */
bool Sort::operator<( const Sort& m_sort ) const
{
  if ( Ecole < m_sort.Ecole )
    return true;
  else if ( Ecole == m_sort.Ecole && Niveau < m_sort.Niveau)
    return true;
  else if ( Ecole == m_sort.Ecole && Niveau == m_sort.Niveau &&
	    Numero < m_sort.Numero )
    return true;
  else
    return false;
}

/** Opérateurs de comparaison "plus grand", nécessaire pour le tri.
 * La comparaison est effectuée de la manière suivante :\n
 * 1) on compare les écoles.
 * 2) si les écoles sont les mêmes, on compare les niveaux.\n
 * 3) si les écoles et les niveaux sont les mêmes, on compare les numéros.
 *
 * Cela permet d'obtenir un conteneur où les sorts sont groupés par
 * écoles, puis par niveau et apparaissent par ordre alphabétique.
 *
 * @param[in] m_sort sort à comparer
 *
 * @return valeur du test
 */
bool Sort::operator>( const Sort& m_sort ) const
{
  if ( Ecole > m_sort.Ecole )
    return true;
  else if ( Ecole == m_sort.Ecole && Niveau > m_sort.Niveau )
    return true;
  else if ( Ecole == m_sort.Ecole && Niveau == m_sort.Niveau &&
	    Numero > m_sort.Numero )
    return true;
  else
    return false;
}

/** Opérateurs d'égalité, nécessaire pour le tri.
 * Ici c'est facile : deux sorts sont égaux si et seulement si tous
 * leurs champs sont rigoureusement identiques.
 *
 * @param[in] m_sort sort à comparer
 *
 * @return valeur du test
 */
bool Sort::operator==( const Sort& m_sort ) const
{
  return ( Ecole == m_sort.Ecole &&
	   Niveau == m_sort.Niveau &&
	   Numero == m_sort.Numero );
}

/**
 * Retourne le numéro de l'école, qui n'est pas accessible de
 * l'extérieur.
 *
 * @return Ecole
 */
unsigned Sort::ecole() const
{
  return Ecole;
}

/**
 * Retourne le niveau du sort, qui n'est pas accessible de
 * l'extérieur.
 *
 * @return Niveau
 */
unsigned Sort::niveau() const
{
return Niveau;
}

/**
 * Retourne le numéro du sort, qui n'est pas accessible de
 * l'extérieur.
 *
 * @return Numero
 */
unsigned Sort::numero() const
{
  return Numero;
}

ostream& operator<<( ostream& out, const Sort& m_sort )
{
  return out << setw(2) << m_sort.Ecole << ' ' << m_sort.Niveau << ' '
	     << setw(2) << m_sort.Numero << ' ';
}
